package tr.edu.metu.is.mega.server.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;

import tr.edu.metu.is.mega.common.dto.BaseDTO;
import tr.edu.metu.is.mega.server.validation.ValidationError;
import tr.edu.metu.is.mega.server.validation.ValidationException;
import tr.edu.metu.is.mega.server.validation.ValidationUtil;

/**
 * Abstract DTO helper implementation which makes data validation before
 * conversion.
 * 
 * @param <T_DTO> type modifier for DTO
 * @param <T_ENTITY> type modifier for entity
 */
public abstract class AbstractDTOHelper<T_DTO extends BaseDTO, T_ENTITY extends BaseEntity> implements DTOHelper<T_DTO, T_ENTITY> {

    /**
     * {@inheritDoc}
     */
    @Override
    public List<T_DTO> toDTO(List<T_ENTITY> entities) {
        List<T_DTO> list = new ArrayList<T_DTO>(entities.size());
        for (T_ENTITY entity : entities) {
            list.add(convertToDTO(entity));
        }
        return list;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<T_ENTITY> toEntity(List<T_DTO> dtos, Class<T_ENTITY> classz) {
        List<T_ENTITY> list = new ArrayList<T_ENTITY>(dtos.size());
        for (T_DTO dto : dtos) {
            T_ENTITY newInstance;
            try {
                newInstance = classz.newInstance();
                toEntity(dto, newInstance);
                list.add(newInstance);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void toEntity(T_DTO dto, T_ENTITY entity) {
        Set<ConstraintViolation<T_DTO>> set = ValidationUtil.getInstance().getValidator().validate(dto, (Class<?>) null);
        if (set.size() > 0) {
            List<ValidationError> list = new ArrayList<ValidationError>();
            for (ConstraintViolation<T_DTO> violation : set) {
                ValidationError error = new ValidationError(violation.getRootBean().getClass().getName(), "", violation.getMessage());
                list.add(error);
            }
            throw new ValidationException(list);
        }
        convertToEntity(dto, entity);
    }

    /**
     * Converts data transfer object to entity.
     * 
     * @param dto data transfer object
     * @param entity entity instance
     */
    public abstract void convertToEntity(T_DTO dto, T_ENTITY entity);

    /**
     * {@inheritDoc}
     */
    @Override
    public T_DTO convertToDTORecursive(T_ENTITY entity) {
        return convertToDTO(entity);
    }

}
